/**
 * 手写 promise
 * **/ 


// 定义promise 状态
const PENDING = 'pending' // 等待
const FULFILLED = 'fulfilled' // 成功
const REJECTED = 'rejected' // 失败


class MyPromise {
  // 构造函数
  constructor(proFun) {
    try {
      proFun(this.resolve, this.reject)
    } catch (error) {
      this.reject()
    }
  }
  
  status = PENDING // 默认等待状态
  value = undefined // 接收成功值
  reason = undefined // 接收失败原因
  
  successCallback = [] // 存储成功回调
  failCallback = [] // 存储失败回调

  // 成功状态
  resolve = (value) => {
    // 判断状态是否已经更改
    if (this.status !== PENDING) return
    // 改变状态
    this.status = FULFILLED
    this.value = value

    // 判断成功函数 是否为空 不为空就执行里面的函数
    // 处理 异步 链式调用 then
    while (this.successCallback.length) {
      // 执行数组第一位 并删除
      this.successCallback.shift()()
    }
  }

  // 失败状态
  reject = (reason) => {
    // 判断状态是否已经更改
    if (this.status !== PENDING) return
    // 改变状态
    this.status = REJECTED
    this.reason = reason
    // 判断成功函数 是否为空 不为空就执行里面的函数
    // 处理 异步 链式调用 then
    while (this.failCallback.length) {
      // 执行数组第一位 并删除
      this.failCallback.shift()()
    }
  }
  
  then(successCallback, failCallback) {
    // 判断是否有回调传递 如果没有就创建一个 接收值并传递
    successCallback = successCallback ? successCallback : value => value
    failCallback = failCallback ? failCallback : reason => { throw reason }

    let mypromise = new MyPromise((resolve, reject) => {
      if (this.status === FULFILLED) {
        setTimeout(() => {
          // 异步处理 同步执行完成之后会创建出 mypromise 对象
          try {
            // 成功后的状态执行
            // successCallback(this.value)
            let result = successCallback(this.value)
            // 对执行结果进行判断
            resultIsPromise(mypromise, result, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0)

      } else if (this.status === REJECTED) {
        // 失败后的状态执行
        // failCallback(this.reason)
        setTimeout(() => {
          try {
            // 成功后的状态执行
            // successCallback(this.value)
            let result = failCallback(this.reason)
            // 对执行结果进行判断
            resultIsPromise(mypromise, result, resolve, reject)
          } catch (error) {
            reject(error)
          }
        }, 0)
      } else {
        // 如果状态是等待 先把 回调push 进数组
        this.successCallback.push(() => {
          setTimeout(() => {
            try {
              // 成功后的状态执行
              // successCallback(this.value)
              let result = successCallback(this.value)
              // 对执行结果进行判断
              resultIsPromise(mypromise, result, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0)
        })
        this.failCallback.push(() => {
          // 失败后的状态执行
          // failCallback(this.reason)
          setTimeout(() => {
            try {
              // 成功后的状态执行
              // successCallback(this.value)
              let result = failCallback(this.reason)
              // 对执行结果进行判断
              resultIsPromise(mypromise, result, resolve, reject)
            } catch (error) {
              reject(error)
            }
          }, 0)
        })
      }
    })
    return mypromise
  }

  catch(failCallback) {
    return this.then(undefined, failCallback)
  }

  finally(cb) {
    // finally方法 不管是 promise 的 then、catch方法都会被调用 
    // 因不论是失败还是成功 finally 都会被执行 所以 直接调用 resolve 成功方法 让finally方法执行
    // 调用 then 方法 执行 回调
    return this.then(value => {
      return MyPromise.resolve(cb()).then(() => value)
    }, error => {
      return MyPromise.resolve(cb()).then(() => { throw error })
    })
  }

  static all(array) {
    let result = [] // 返回数组
    let number = 0 // 计数
    return new MyPromise((resolve, reject) => {
      for (let index = 0; index < array.length; index++) {
        let item = array[index]
        if (item instanceof MyPromise) {
          // 如果是 promise 对象先执行 获取结果
          item.then(val => {
            recognitionFun(index, val)
          }, reason => {
            reject(reason)
          })
        } else {
          // 普通对象 直接赋值
          recognitionFun(index, array[index])
        }
      }

      // 处理数据
      function recognitionFun(index, val) {
        result[index] = val
        // 每次调用后 number 加1 当number 与 array的length相同时调用resolve 返回结果
        number++
        if (number === array.length) resolve(result)
      }

    })
  }

  static resolve(data) {
    // 只有成功状态 不存在失败 返回的是一个promise 对象 如果接收值不是promise 对象 就创建一个promise 对象返回
    if (data instanceof MyPromise) data
    return new MyPromise(resolve => resolve(data))
  }
}


const resultIsPromise = (mypromise, result, resolve, reject) => {

  if (mypromise === result) {
    return reject(new TypeError('同一个mypromise对像。'))
  }
  // 判断 result 是否是 promise 对象
  if (result instanceof MyPromise) {
    // promise 执行 返回结果
    result.then(val => resolve(val), err => reject(err))
  } else {
    resolve(result)
  }
}

module.exports = MyPromise
